package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.IpUtil;
import io.netty.handler.codec.HeadersUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @Author: zm
 * @Date: 2021/8/20 19:46
 */
@Component
public class AuthGlobalFilter implements GlobalFilter {

    @Autowired
    private RedisTemplate redisTemplate;


    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Value("${authUrls.url}")
    private String authUrls;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //  用户不能通过浏览器访问内部数据接口！
        //  获取用户请求的url 路径
        ServerHttpRequest request = exchange.getRequest();
        //  获取到请求路径
        //  getURI(); 相当于获取整个url 的路径
        //  getURI().getPath(); 相当于获取到/api/product/inner/getSkuInfo/44
        //  http://localhost/api/product/inner/getSkuInfo/17
        String path = request.getURI().getPath();

        // 内部访问地址不允许访问 //  看这个请求路径是否是属于内部数据接口！
        if (antPathMatcher.match("/**/inner/**", path)) {
            //  应该做出响应
            ServerHttpResponse response = exchange.getResponse();
            return out(response, ResultCodeEnum.PERMISSION);
        }

        //  获取用户Id 存储在缓存中的，key = token 组成
        //  userId 返回 -1 的话，相当于用户盗用了token ，不能正常返回userId
        String userId = getUserId(request);
        String userTempId = this.getUserTempId(request);

        // ip 地址对不上也不允许访问
        if ("-1".equals(userId)) {
            ServerHttpResponse response = exchange.getResponse();
            return out(response, ResultCodeEnum.PERMISSION);
        }

        //  判断用户是否访问带有 这样的资源路径 /api/**/auth/** ，则用户必须登录！
        //  path =item.gmall.com/api/aaa/bbb/auth/findAll
        if (antPathMatcher.match("/api/**/auth/**", path)) {
            if (StringUtils.isEmpty(userId)) {
                ServerHttpResponse response = exchange.getResponse();
                return out(response, ResultCodeEnum.LOGIN_AUTH);
            }
        }

        //  判断用户访问的控制器 是否在 authUrl 变量中！
        //  authUrl=trade.html,myOrder.html,list.html
        //  http://list.gmall.com/list.html?category3Id=61
        String[] split = authUrls.split(",");
        for (String url : split) {
            //  表示用户访问的路径中包含 上述的控制器 ,但是，此时用户未登录
            if (path.indexOf(url) != -1 && StringUtils.isEmpty(userId)) {
                //  如果是上述情况则需要跳转到登录页面！
                ServerHttpResponse response = exchange.getResponse();

                response.setStatusCode(HttpStatus.SEE_OTHER);
                //  设置跳转的页面
                response.getHeaders().add(HttpHeaders.LOCATION, "http://passport.gmall.com/login.html?originUrl=" + request.getURI());
                //  设置一下重定向
                return response.setComplete();
            }
        }

//        // 则需要将用户Id 进行保存 ！ 记住的！
//        if (!StringUtils.isEmpty(userId)) {
//            // request 对象 request 本身就是 ServerHttpRequest
//            request.mutate().header("userId", userId).build();
//            //  返回数据
//            return chain.filter(exchange.mutate().request(request).build());
//        }
        // 则需要将用户Id或临时用户ID 进行保存 ！ 记住的！
        if (!StringUtils.isEmpty(userId) || !StringUtils.isEmpty(userTempId)) {
            // request 对象 request 本身就是 ServerHttpRequest
            if (!StringUtils.isEmpty(userId)) {
                request.mutate().header("userId", userId).build();
            }
            if (!StringUtils.isEmpty(userTempId)) {
                request.mutate().header("userTempId", userTempId).build();
            }

            //  返回数据
            return chain.filter(exchange.mutate().request(request).build());
        }
        return chain.filter(exchange);

    }


    /**
     * 提示用户方法
     *
     * @param response
     * @param permission
     * @return
     */
    private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum permission) {
        //  将用户提示的信息输入到页面！
        Result<Object> result = Result.build(null, permission);
        //  此时，需要将result 这个对象转换为字符串
        String str = JSONObject.toJSONString(result);
        //  有了数据流
        DataBuffer wrap = response.bufferFactory().wrap(str.getBytes());
        //  要输出内容，则需要设置一下页面的格式！
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");

        //  将用户信息写入到页面！
        //  Publisher<? extends DataBuffer> body
        return response.writeWith(Mono.just(wrap));
    }


    /**
     * 获取临时用户ID
     *
     * @param request
     * @return
     */
    private String getUserTempId(ServerHttpRequest request) {
        String userTempId = "";

        HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
        if (httpCookie != null) {
            userTempId = httpCookie.getValue();
        } else {
            List<String> list = request.getHeaders().get("userTempId");
            if (!CollectionUtils.isEmpty(list)) {
                userTempId = list.get(0);
            }
        }
        return userTempId;
    }

    /**
     * 获取用户Id方法
     *
     * @param request
     * @return
     */
    private String getUserId(ServerHttpRequest request) {
        //  用户Id 存储在缓存中的 缓存的key = user:token
        //  如何获取token ： cookie 或者 header 中！
        String token = "";
        //  从header 中获取token
        List<String> stringList = request.getHeaders().get("token");
        if (!CollectionUtils.isEmpty(stringList)) {
            token = stringList.get(0);
        } else {
            //  从cookie 中获取
            //  HttpCookie httpCookie1 = request.getCookies().get("token").get(0);
            HttpCookie httpCookie = request.getCookies().getFirst("token");
            if (httpCookie != null) {
                token = httpCookie.getValue();
            }
        }

        //  组成缓存key
        if (!StringUtils.isEmpty(token)) {
            String key = "user:login:" + token;
            //  获取缓存的数据
            String strJson = (String) redisTemplate.opsForValue().get(key);

            //  进行判断ip 地址是否正确
            JSONObject jsonObject = JSON.parseObject(strJson, JSONObject.class);
            String ip = (String) jsonObject.get("ip");
            //  缓存的Ip 地址与 要登录的ip 地址进行比较
            if (ip.equals(IpUtil.getGatwayIpAddress(request))) {
                //  获取缓存中的userId
                String userId = (String) jsonObject.get("userId");
                return userId;
            } else {
                //  有人在盗用token 获取登录权限
                return "-1";
            }
        }
        return null;
    }
}
